
package com.dg.acb.utils;

import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;

public final class DoubleKeyMap<FirstKey, SecondKey, Value> {
    private final HashMap<FirstKey, Entry<FirstKey, SecondKey, Value>> mFirstKMap;
    private final HashMap<SecondKey, Entry<FirstKey, SecondKey, Value>> mSecondKMap;

    public DoubleKeyMap() {
        mFirstKMap = new HashMap<FirstKey, Entry<FirstKey, SecondKey, Value>>();
        mSecondKMap = new HashMap<SecondKey, Entry<FirstKey, SecondKey, Value>>();
    }

    public boolean containsFirstKey(FirstKey k) {
        return mFirstKMap.containsKey(k);
    }

    public boolean containsSecondKey(SecondKey v) {
        return mSecondKMap.containsKey(v);
    }

    public Value getValueByFirstKey(FirstKey firstKey) {
        Entry<FirstKey, SecondKey, Value> entry = mFirstKMap.get(firstKey);
        if (entry != null) {
            return entry.value;
        }
        return null;
    }

    public Value getValueBySecondKey(SecondKey secondKey) {
        Entry<FirstKey, SecondKey, Value> entry = mSecondKMap.get(secondKey);
        if (entry != null) {
            return entry.value;
        }
        return null;
    }

    public SecondKey getSecondKey(FirstKey firstKey) {
        Entry<FirstKey, SecondKey, Value> entry = mFirstKMap.get(firstKey);
        if (entry != null) {
            return entry.secondKey;
        }
        return null;
    }

    public FirstKey getFirstKey(SecondKey secondKey) {
        Entry<FirstKey, SecondKey, Value> entry = mSecondKMap.get(secondKey);
        if (entry != null) {
            return entry.firstKey;
        }
        return null;
    }

    public Set<FirstKey> firstKeySet() {
        return mFirstKMap.keySet();
    }

    public Set<SecondKey> secondKeySet() {
        return mSecondKMap.keySet();
    }

    public boolean put(FirstKey key1, SecondKey key2, Value value) {
        Objects.requireNonNull(key1);
        Objects.requireNonNull(key2);
        Objects.requireNonNull(value);
        if (mFirstKMap.containsKey(key1) || mSecondKMap.containsKey(key2)) {
            throw new IllegalArgumentException("firstKey or secondKey already exist");
        }
        Entry<FirstKey, SecondKey, Value> entry = new Entry<FirstKey, SecondKey, Value>(key1, key2, value);
        mFirstKMap.put(key1, entry);
        mSecondKMap.put(key2, entry);
        return true;
    }

    public Collection<Value> values() {
        Set<Value> values = new HashSet<Value>();
        Collection<Entry<FirstKey, SecondKey, Value>> entrys = mFirstKMap.values();
        for (Entry<FirstKey, SecondKey, Value> entry : entrys) {
            values.add(entry.value);
        }
        return values;
    }

    public void clear () {
        mFirstKMap.clear();
        mSecondKMap.clear();
    }

    public int size () {
        return mFirstKMap.size();
    }

    private static class Entry <FirstKey, SecondKey, Value>{
        public final FirstKey firstKey;
        public final SecondKey secondKey;
        public final Value value;
        public Entry(FirstKey firstKey, SecondKey secondKey, Value value) {
            this.firstKey = firstKey;
            this.secondKey = secondKey;
            this.value = value;
        }
    }
}
